/*
 * Copyright (C) 2010,2011  Paulo Cesar Pereira de Andrade.
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * Authors:
 *	Paulo Cesar Pereira de Andrade
 */

/*
 * Prototypes
 */
#if PROTO
static void
vc_neg_vc(vc_t *u, vc_t *v, eint32_t m);

static void
vs_neg_vs(vs_t *u, vs_t *v, eint32_t m);

static void
vi_neg_vi(vi_t *u, vi_t *v, eint32_t m);

static void
vl_neg_vl(vl_t *u, vl_t *v, eint32_t m);

static void
vf_neg_vf(vf_t *u, vf_t *v, eint32_t m);

static void
vd_neg_vd(vd_t *u, vd_t *v, eint32_t m);

static void
vo_neg_vo(vo_t *u, vo_t *v, eint32_t m);
#endif

/*
 * Implementation
 */
#if CODE
void
evector_neg(evector_t *v, etype_t t)
{
    eint32_t	 l;
    evector_t	*r;
    etype_t	 rt;
    v_enter();

    v_check(2);
    l = v->length;

    rt = match(t, t, 0, 0);
    if (rt != t)
	v = coerce(v, t, rt);
    r = create(v, rt);

    switch (rt) {
	case t_int8:
	    vc_neg_vc(r->v.obj, v->v.obj, vc_length(l));
	    break;
	case t_int16:
	    vs_neg_vs(r->v.obj, v->v.obj, vs_length(l));
	    break;
	case t_int32:
	    vi_neg_vi(r->v.obj, v->v.obj, vi_length(l));
	    break;
	case t_int64:
	    vl_neg_vl(r->v.obj, v->v.obj, vl_length(l));
	    break;
	case t_float32:
	    vf_neg_vf(r->v.obj, v->v.obj, vf_length(l));
	    break;
	case t_float64:
	    vd_neg_vd(r->v.obj, v->v.obj, vd_length(l));
	    break;
	default:
	    vo_neg_vo(r->v.obj, v->v.obj, l);
	    break;
    }
    v_leave();
}

static void
vc_neg_vc(vc_t *u, vc_t *v, eint32_t m)
{
    while (m--)
	*u++ = -*v++;
}

static void
vs_neg_vs(vs_t *u, vs_t *v, eint32_t m)
{
    while (m--)
	*u++ = -*v++;
}

static void
vi_neg_vi(vi_t *u, vi_t *v, eint32_t m)
{
    while (m--)
	*u++ = -*v++;
}

static void
vl_neg_vl(vl_t *u, vl_t *v, eint32_t m)
{
    while (m--)
	*u++ = -*v++;
}

static void
vf_neg_vf(vf_t *u, vf_t *v, eint32_t m)
{
    while (m--)
	*u++ = -*v++;
}

static void
vd_neg_vd(vd_t *u, vd_t *v, eint32_t m)
{
    while (m--)
	*u++ = -*v++;
}

static void
vo_neg_vo(vo_t *u, vo_t *v, eint32_t m)
{
    eint_t	 i;

    for (; m; u++, v++, m--) {
	switch (eobject_type(*v)) {
	    case t_void:
		set_i(0);
		break;
	    case t_int:
		if (likely((i = get_i(v)) != MININT))
		    set_i(-i);
		else {
		    empz_set_u(thr_zr, MININT);
		    set_z(thr_zr);
		}
		break;
	    case t_float:
		set_d(-get_d(v));
		break;
	    case t_mpz:
		mpz_neg(thr_zr, get_z(v));
		set_z(thr_zr);
		break;
	    case t_mpq:
		mpq_neg(thr_qr, get_q(v));
		set_q(thr_qr);
		break;
	    case t_mpr:
		mpfr_neg(thr_rr, get_r(v), thr_rnd);
		set_r(thr_rr);
		break;
	    case t_cdd:
		set_dd(-get_dd(v));
		break;
	    case t_cqq:
		cqq_neg(thr_qq, get_qq(v));
		set_qq(thr_qq);
		break;
	    case t_mpc:
		mpc_neg(thr_c, get_cc(v), thr_rndc);
		set_cc(thr_c);
		break;
	    default:
		eraise_exception(except_not_a_number);
	}
    }
}
#endif
